package cn.xiaosiyuan.javaagenthelloworld;

import javassist.*;

import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.Date;

public class TomcatMonitor {
    final static String source = "{\n" +
//            "        Object result;\n" +
            "        try {\n" +
//            "            result = ($w)%s$agent($$);\n" +
            "            return result = ($w)%s$agent($$);\n" +
            "        } finally {\n" +
            " Date t = new Date();\n" +
            "System.out.println(\"testsource\");"+
            "SimpleDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n" +
            "System.out.println(oldMethod.getName() + df.format(t));" +
            "        }\n" +
//            "        return ($r) result;\n" +
            "    }";

    final static String voidSource = "{\n" +
            "        long begin = System.currentTimeMillis();\n" +
            "        try {\n" +
            "            %s$agent($$);\n" +
            "        } finally {\n" +
            " Date t = new Date();\n" +
            "System.out.println(\"testnosource\");"+
            "SimpleDateFormat df = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n" +
            "System.out.println(oldMethod.getName() + df.format(t));" +
            "        }\n" +
            "    }";


    //    不写一个空的main，maven在install的时候会报错
    public static void main(String[] args) {

    }

// cn.xiaosiyuan.javaagenthelloworld.*

// 读取参数配置

// 匹配类

// 获取这个类下的所有方法

    // 改造这个方法
    public static void premain(String arg, Instrumentation instrumentation) throws NotFoundException {
        final String config = arg;
//        final ClassPool pool = new ClassPool();

        ClassPool pool = ClassPool.getDefault();
//        在tomcat环境下运行，方法1
        //在tomcat环境下，向pool插入一个类对象的搜索路径
//        pool.appendClassPath("E:\\xxx\\xxx\\target\\xxx_war\\WEB-INF\\lib\\xxx_jar-0.0.1-SNAPSHOT.jar");

//        pool.appendClassPath("D:\\work\\xikuan\\biz\\out\\artifacts\\auditSystem_war_exploded\\WEB-INF\\lib\\xp-framework.jar");
//        pool.appendClassPath("D:\\personal\\comprehensive\\out\\artifacts\\auditSystem_war_exploded\\WEB-INF\\lib\\xp-framework.jar");

//        pool.insertClassPath(new URLClassPath("localhost", 8082, "/WEB-INF/lib", "xp-framework"));

//        在tomcat环境下运行，方法2
//        ClassClassPath classPath = new ClassClassPath(this.getClass());
//        pool.insertClassPath(classPath);

        pool.appendSystemPath();
        instrumentation.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

//                -javaagent:D:\personal\javaagenthelloworld\out\artifacts\javautil_jar\javautil.jar=cn.xiaosiyuan.javaagenthelloworld.UserService
//                这里config就是cn.xiaosiyuan.javaagenthelloworld.UserService


                if(className == null || !className.replaceAll("/",".").startsWith("com.oneheart.xp.plugin.auditSystem")){
                    return null;
                }

//                if(className == null || !className.replaceAll("/",".").startsWith("config")){
//                    return null;
//                }
//                if (!"com/oneheart/xp".equals(className)){
//                    return null;
//                }

                try {
//                    在tomcat环境下运行，方法2
//                    ClassClassPath classPath = new ClassClassPath(this.getClass());
//                    pool.insertClassPath(classPath);

                    className = className.replaceAll("/",".");
                    CtClass ctClass = pool.get(className);
//                获取它的所有方法
                    for (CtMethod declaredMethod:ctClass.getDeclaredMethods()) {
//                        newMethod(declaredMethod);

                        Date date = new Date();
                        System.out.print(date.toString());
                        System.out.print("  类名： " + className);
                        System.out.println("  方法名： " + declaredMethod.getName());
                    }
                    return ctClass.toBytecode();
                } catch (NotFoundException e) {
                    e.printStackTrace();
                } catch (CannotCompileException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });

    }

    public static CtMethod newMethod(CtMethod oldMethod) throws CannotCompileException, NotFoundException {
        CtMethod copy = CtNewMethod.copy(oldMethod, oldMethod.getDeclaringClass(), null);
        copy.setName(oldMethod.getName() + "$agent");
        oldMethod.getDeclaringClass().addMethod(copy);

        if (oldMethod.getReturnType().equals(CtClass.voidType)){
            oldMethod.setBody(String.format(voidSource,oldMethod.getName()));
        }else {
            oldMethod.setBody(String.format(source,oldMethod.getName()));
        }
        return copy;
    }

}
